import cherrypy
from Cheetah.Template import Template
import dailyspents.util as util
from GenericView import GenericView
from dailyspents.model.Spent import Spent
from dailyspents.model.Payment import Payment
from dailyspents.model.Category import Category
from dailyspents.model.Local import Local
import datetime

try:
    import gdchart
except:
    pass

from dailyspents.csvUtil import importCSV
import os
from os.path import join

class SpentView(GenericView):
    
    def __init__(self):
        GenericView.__init__(self)
    
    @cherrypy.expose
    def index(self, message=None, errorMessage=None, page='newspent', **kargs):
        
        GenericView.index(self, message, errorMessage)
        
        realPage = ''
        
        if page == 'newspent':
            realPage = "insertSpent.html"
        elif page == 'filter':
            realPage = "filter.html"
        elif page == 'edit':
            return self.prepareEdit(int(kargs['id']))
        elif page == 'importCSV':
            realPage = 'importCSV.html'
        else:
            raise cherrypy.HTTPRedirect('/index')
            
        return Template(file=join(util.HTMLPATH, realPage),
                        searchList=[self.nameSpace]).respond()
    
    @cherrypy.expose
    def newPayment(self, **kargs):
        cherrypy.response.headers['content-type'] = 'application/xml'
        paymentName = kargs.get('name', '')
        
        try:
            if paymentName == '':
                raise
            payment = Payment()
            payment.name = paymentName
            payment.user = self.user
            self.paymentController.save(payment)
            self.message = "New payment inserted sucefully."
        except Exception, e:
            print '[an exception occurred] >>>', e
            return '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                    <erro>1</erro>
                    <message>The new payment could not be inserted.</message>'''
        
        return '''<?xml version="1.0" encoding="utf-8"?>
                  <response>
                    <erro>0</erro>
                    <message></message>
                    <optName>'''+payment.name+'''</optName>
                    <optValue>'''+str(payment.id)+'''</optValue>
                    <method>addOption</method>
                    <elementName>paymentId</elementName>
                  </response>'''
    
    @cherrypy.expose
    def newCategory(self, **kargs):
        cherrypy.response.headers['content-type'] = 'application/xml'
        categoryName = kargs.get('name', '')
        
        try:
            if categoryName == '':
                raise
            category = Category()
            category.name = categoryName
            category.user = self.user
            self.categoryController.save(category)
            self.message = "New category inserted sucefully."
        except Exception, e:
            print '[an exception occurred] >>>', e
            #self.message = 'Invalid name.'
            #raise cherrypy.HTTPRedirect("/spent?errorMessage="+self.message)
            return '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                    <erro>1</erro>
                    <message>The new category could not be inserted.</message>'''
        
        return '''<?xml version="1.0" encoding="utf-8"?>
                  <response>
                    <erro>0</erro>
                    <message></message>
                    <optName>'''+category.name+'''</optName>
                    <optValue>'''+str(category.id)+'''</optValue>
                    <method>addOption</method>
                    <elementName>categoryId</elementName>
                  </response>'''
    
    @cherrypy.expose
    def newLocal(self, **kargs):
        cherrypy.response.headers['content-type'] = 'application/xml'
        newLocalName = kargs.get('name', None)
        
        try:
            
            if newLocalName == None or newLocalName == '':
                raise Exception('Invalid new local name.')
            
            newLocal = Local(name=newLocalName, user=self.user)
            self.localController.save(newLocal)
            self.message = 'New local inserted sucefully.'
            
        except Exception, e:
            print '[an exception occurred] >>>', e
            return '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                    <erro>1</erro>
                    <message>The new local could not be inserted.</message>'''
        
        return '''<?xml version="1.0" encoding="utf-8"?>
                  <response>
                    <erro>0</erro>
                    <message></message>
                    <optName>'''+newLocal.name+'''</optName>
                    <optValue>'''+str(newLocal.id)+'''</optValue>
                    <method>addOption</method>
                    <elementName>localId</elementName>
                  </response>'''
    
    def prepareEdit(self, id, errorMessage=None, message=None):
        try:
            spent = self.spentController.getById(id)
            self.nameSpace['spent'] = spent
            self.nameSpace['errorMessage'] = errorMessage
            msg = self.nameSpace['message'] = message
            
            return Template(file=join(util.HTMLPATH, "editSpent.html"), 
                        searchList=[self.nameSpace]).respond()
        except Exception, e:
            raise e
    
    @cherrypy.expose
    def edit(self, **kargs):
        
        self.checkAuthentication()
        
        try:
            spent = self.spentController.getById(int(kargs['id']))
            self.fillSpent(spent, **kargs)
            self.spentController.save(spent)
            
            return self.prepareEdit(spent.id, message = 'Item edited sucefully.')
        except Exception, e:
            print '[an exception occurred] >>>', e
            return self.prepareEdit(spent.id,
                            errorMessage = 'Invalid inserted data.')
        
    @cherrypy.expose                    
    def insertSpent(self, **kargs):
        self.checkAuthentication()
        
        try:

            newSpent = Spent()
            newSpent.user = self.user
            self.fillSpent(newSpent, **kargs)
            
            self.spentController.save(newSpent)
            self.message = "New spent sucefully inserted."
            
        except Exception, e:
            print '[an exception occurred] >>>', e
            raise e
            self.message = 'Invalid inserted data.'
            raise cherrypy.HTTPRedirect("/spent/index?errorMessage="+self.message)
        
        raise cherrypy.HTTPRedirect("/spent/index?message="+self.message)
    
    def fillSpent(self, spent, **kargs):
        '''Fills a spent object with posted params'''
        
        categoryId = kargs.get('categoryId')
        paymentId = kargs.get('paymentId')
        localId = kargs.get('localId')
        
        if categoryId == '':
            categoryId = 0
            
        if paymentId == '':
            paymentId = 0
            
        if localId == '':
            localId = 0
        
        cat = self.categoryController.getById(int(categoryId))
        spent.category = cat
        
        payment = self.paymentController.getById(int(paymentId))
        spent.payment = payment
        
        local = self.localController.getById(int(localId))
        spent.local = local
        
        spent.value = eval(kargs['value'])
        spent.description = kargs['description']
        
        date = kargs['date'].split('-')
        spent.date = datetime.date(int(date[0]), int(date[1]), int(date[2]))
                 
    @cherrypy.expose
    def filter(self, **kargs):
        
        self.checkAuthentication()
        
        self.nameSpace = self.makeCommonNamespace()
        self.makeContextMenu()
        self.nameSpace['contextMenu'].append(('Show statistics', 
                '/spent/makeStatistics'))
        self.nameSpace['doNavigation'] = False
        
        dateMin = kargs.get('from', None)
        dateMax = kargs.get('to', None)
        value = kargs.get('value', None)
        cat = kargs.get('categoryId', None)
        pay = kargs.get('paymentId', None)
        local = kargs.get('localId', None)
        
        if cat == "": cat = None
        
        if pay == '': pay = None
        
        if local == '': local = None
            
        if dateMin == "": dateMin = None
            
        if dateMax == "": dateMax = None
        
        if value == "": value = None
        
        spents = self.spentController.filter((dateMin, dateMax), value, cat,
            pay, local)
        
        self.nameSpace['spents'] = spents
        cherrypy.session['spents'] = spents
        
        if int(kargs.get('showStatistics', 0)) == 1:
            return self.makeStatistics()
        
        return Template(file=join(util.HTMLPATH, "main.html"),
                        searchList=[self.nameSpace]).respond()
                        
    @cherrypy.expose
    def makeStatistics(self, **kargs):
        
        self.checkAuthentication()
        
        total = 0
        
        #a dict mapping each category to a tuple with its total and percentage
        #eg.: {'cat': (10, 23.5)}
        totalPerCategory = {}
        
        #a dict mapping each payment to a tuple with its total and percentage
        #eg.: {'pay': (10, 23.5)}
        totalPerPayment = {}
        
        spents = cherrypy.session.get('spents', [])
        
        for spent in spents:
            total += spent.value
            
            catAtualValue = spent.value + totalPerCategory.get(
                    spent.category.name, (0,0))[0]
                    
            totalPerCategory[spent.category.name] = (catAtualValue, 
                    (catAtualValue*100)/total)
            
            payAtualValue = spent.value + totalPerPayment.get(
                    spent.payment.name, (0,0))[0]
                        
            totalPerPayment[spent.payment.name] = (payAtualValue, 
                    (payAtualValue*100)/total)
        
        self.__createCategoryChart(totalPerCategory)
        self.__createPaymentChart(totalPerPayment)
        #self.__createLineChart(spents)
        
        #configure the specific nameSpace
        self.nameSpace = self.makeCommonNamespace()
        self.nameSpace['totalPerCategory'] = totalPerCategory
        self.nameSpace['totalPerPayment'] = totalPerPayment
        self.nameSpace['total'] = total
        
        self.makeContextMenu()
        
        return Template(file=join(util.HTMLPATH, "showStatistics.html"),
                        searchList=[self.nameSpace]).respond()
    
    #def __createLineChart(self, spents):
    #    byYearData = {}
    #    byMonthData = {}
    #    byCatData= {}
    #    
    #    for s in spents:
    #        byYearData[s.date.year] = s.value + byYearData.get(s.date.year, 0)
    #        monthYear = str(s.date.year) + '/' + str(s.date.month)
    #        byMonthData[monthYear] = s.value + byMonthData.get(monthYear, 0)
    #        
    #        catName = s.category.name
    #        catSpecificDict = byCatData.get(catName, {})
    #        catSpecificDict[monthYear] = catSpecificDict.get(monthYear, 0) + s.value
    #        byCatData[catName] = catSpecificDict
    #        
    #    if len(byYearData.keys()) > 1:
    #        totalData = byYearData
    #    elif len(byMonthData.keys()) > 1:
    #        totalData = byMonthData
    #    else:
    #        return
    #    
    #    chart = gdchart.Line()
    #    labels = totalData.keys()
    #    labels.sort()
    #    allLists = []
    #    
    #    listTotalData = []
    #    for label in labels:
    #        listTotalData.append(totalData[label])
    #    
    #    allLists.append(listTotalData)
    #    
    #    for k,v in byCatData.items():
    #        specificCat = []
    #        
    #        for l in labels:
    #            specificCat.append(v.get(l, 0))
    #            
    #        allLists.append(specificCat)
    #    print chart.getAllOptions()
    #    chart.setData(*(i for i in allLists))
    #    chart.setLabels(labels)
    #    chart.ytitle = self.user.settings.currency
    #    chart.xtitle = 'time'
    #    chart.title = 'Spent Progress'
    #    
    #    chart.bg_color = gdchart.rgbFactory('white')
    #    chart.width = 700
    #    chart.height = 300
    #    chart.ext_color = util.COLORS[: len(allLists)]
    #    chart.draw(join(util.WEBPATH,'tmp','line'+cherrypy.session['_id']+'.png'))
    
    def __createCategoryChart(self, totalPerCategory):
        #create the cateogry chart
        chartCategory = gdchart.Bar3D()
        
        dataSorted = totalPerCategory.items()
        dataSorted.sort(lambda x, y: cmp(y[1][0], x[1][0]))
        
        chartCategory.setData(list(value[1][0] for value in dataSorted))
        chartCategory.setLabels(list(value[0] for value in dataSorted))
        chartCategory.bg_color = gdchart.rgbFactory('white')
        chartCategory.width = 350
        chartCategory.height = 300
        chartCategory.ytitle = self.user.settings.currency
        chartCategory.xtitle = 'category'
        
        chartCategory.ext_color = util.COLORS[:len(totalPerCategory.keys())]
        
        chartCategory.draw(join(util.WEBPATH, 'tmp', 'category' +
                                cherrypy.session['_id'] + '.png'))
    
    def __createPaymentChart(self, totalPerPayment):
        #create the payment chart
        payCategory = gdchart.Bar3D()
        
        dataSorted = totalPerPayment.items()
        dataSorted.sort(lambda x, y: cmp(y[1][0], x[1][0]))
        
        payCategory.setData(list(value[1][0] for value in dataSorted))
        payCategory.setLabels(list(value[0] for value in dataSorted))
        payCategory.bg_color = gdchart.rgbFactory('white')
        payCategory.width = 350
        payCategory.height = 300
        payCategory.ytitle = self.user.settings.currency
        payCategory.xtitle = 'payment'
        
        payCategory.ext_color = util.COLORS[:len(totalPerPayment.keys())]
        
        payCategory.draw(join(util.WEBPATH, 'tmp', 'payment'+
                              cherrypy.session['_id'] + '.png'))
    
    @cherrypy.expose
    def commaSeparatedVersion(self):
        
        self.checkAuthentication()
        
        outputText = ''
        
        for s in cherrypy.session['spents']:
            line = (s.category.name, s.payment.name, str(s.date), 
                    s.description, str(s.value))
            outputText += ','.join(line) + '\n'
        
        fileName = join(util.WEBPATH, 'tmp', 'csv' + cherrypy.session['_id'] + '.txt')
                        
        fileOutput = open(fileName, 'w')
        fileOutput.write(outputText)
        fileOutput.close()
        
        return file(fileName)

    @cherrypy.expose
    def postCSVFile(self, csvFile):
        
        self.checkAuthentication()
        
        fileName = join(util.WEBPATH, 'tmp', 'csvSource' +
                        cherrypy.session['_id'] + '.txt')
        fileSource = open(fileName, 'w')
        fileSource.write(str(csvFile).encode('utf-8'))
        fileSource.close()
        
        importCSV(fileName, cherrypy.session['user'])
        
        os.remove(fileName)
        
        self.makeCommonNamespace()
        self.makeContextMenu()
        self.message = 'CSV imported sucefully'
        
        raise cherrypy.HTTPRedirect("/index?page=importCSV&message=" +
                                        self.message)
